查看原文
其他

【第2191期】ECMAScript2021新特征

五米 前端早读课 2021-01-29

前言

今日前端早读课文章由凹凸实验室@五米授权分享。

正文从这开始~~

ECMAScript 2021版本预计在2021年6月发布,根据每年的新特性都会经历四个阶段,而第四阶段也就是最后一个阶段,本文即将介绍的即提案4中的相关新特性,意味着这些新特性将很大程度的出现在下一个版本中。

新特性总结如下:

  • String.prototype.replaceAll( )

  • 私有方法 Private Methods 与私有访问者 Private Accessors

  • Promise.any 与 AggregateError

  • WeakRefs 弱引用

  • 逻辑运算符和赋值表达式

String.prototype.replaceAll( )

完全匹配替换字符串

目前,JavaScript字符串有replace方法可以用来做一个字符串替换,

  1. const str = "Backbencher sits at the Back"

  2. const newStr = str.replace("Back", "Front")

  3. console.log(newStr) // "Frontbencher sits at the Back"

如果是要完全匹配我们只能用正则表达式,如下

  1. const str = "Backbencher sits at the Back"

  2. const newStr = str.replace(/Back/g, "Front")

  3. console.log(newStr) // "Frontbencher sits at the Front"

使用replaceAll

  1. const str = "Backbencher sits at the Back"

  2. const newStr = str.replaceAll("Back", "Front")

  3. console.log(newStr) // "Frontbencher sits at the Front"

私有方法 Private Methods

私有方法

私有方法只能在定义它的类内部访问,专用方法名称以开头 #

  1. class Person {


  2. // Private method

  3. #setType() {

  4. console.log("I am Private");

  5. }


  6. // Public method

  7. show() {

  8. this.#setType();

  9. }


  10. }


  11. const personObj = new Person()

  12. personObj.show() // "I am Private"

  13. personObj.setType() // TypeError: personObj.setType is not a function

由于setType()是私有方法,所以personObj.setType返回undefined,用undefined作函数会 引发TypeError。

私有访问者 Private Accessors

私有访问者

可以通过 #在函数名称前添加访问器函数来使其私有

  1. class Person {

  2. // Public accessor

  3. get name() { return "Backbencher" }

  4. set name(value) {}


  5. // Private accessor

  6. get #age() { return 42 }

  7. set #age(value) {}

  8. }

在上面的代码get和set关键字中,创建name了一个accessor属性。使name看起来像一个函数,也可以像普通属性一样读取它, 而age则是私有。

  1. const obj = new Person()

  2. console.log(obj.name) // "Backbencher"

  3. console.log(obj.age) // undefined

Promise.any 与 AggregateError

当Promise列表中的任意一个promise成功resolve则返回第一个resolve的结果状态, 如果所有的promise均reject,则抛出异常表示所有请求失败

  1. Promise.any([

  2. new Promise((resolve, reject) => setTimeout(reject, 200, 'Third')),

  3. new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Second')),

  4. new Promise((resolve, reject) => setTimeout(resolve, 2000, 'First')),

  5. ])

  6. .then(value => console.log(`Result: ${value}`)) // Result: Second

  7. .catch (err => console.log(err))

另一种情况

  1. Promise.any([

  2. Promise.reject('Error 1'),

  3. Promise.reject('Error 2'),

  4. Promise.reject('Error 3')

  5. ])

  6. .then(value => console.log(`请求结果: ${value}`))

  7. .catch (err => console.log(err)) //AggregateError: All promises were rejected

Promise.any与Promise.race十分容易混淆,务必注意区分,Promise.race 一旦某个promise触发了resolve或者reject,就直接返回了该状态结果,并不在乎其成功或者失败。

WeakRefs

使用WeakRefs的Class类创建对对象的弱引用

当我们通过(const、let、var)创建一个变量时,垃圾收集器GC将永远不会从内存中删除该变量,只要它的引用仍然存在可访问。而WeakRef对象包含对对象的弱引用,对对象的弱引用是不会阻止垃圾收集器GC恢复该对象的引用,则GC可以在任何时候删除它,目前,可以通过WeakMap()或者WeakSet()来使用WeakRefs。

举个例子:想要跟踪特定的对象调用某一特定方法的次数,超过1000条则做对应提示

  1. let map = new Map()

  2. function doSomething(obj){

  3. ...

  4. }

  5. function useObject(obj){

  6. doSomething(obj)

  7. let called = map.get(obj) || 0

  8. called ++

  9. if(called>1000){

  10. console.log('当前调用次数已经超过1000次了')

  11. }

  12. map.set(obj, called)

  13. }

如上虽然可以实现我们的功能,但是会发生内存溢出,因为传递给doSomething函数的每个对象都永久保存在map中,并且不会被GC回收,因此我们可以使用WeakMap

  1. let wmap = new WeakMap()

  2. function doSomething(obj){

  3. ...

  4. }

  5. function useObject(obj){

  6. doSomething(obj)

  7. let called = wmap.get(obj) || 0

  8. called ++

  9. if(called>1000){

  10. console.log('当前调用次数已经超过1000次了')

  11. }

  12. wmap.set(obj, called)

  13. }

因为是弱引用,所以WeakMap、WeakSet的键值对是不可枚举的 WeakSet和WeakMap相似,但是每个对象在WeakSet中的每个对象只可能出现一次,WeakSet中所有对象都是唯一的

  1. let ws = new WeakSet()

  2. let foo = {}

  3. let bar = {}


  4. ws.add(foo)

  5. ws.add(bar)


  6. ws.has(foo) //true

  7. ws.has(bar) //true


  8. ws.delete(foo) //删除foo对象

  9. ws.has(foo) //false 已删除

  10. ws.has(bar) //仍存在

WeakSet与Set相比有以下两个区别

  • WeakSet只能是对象集合,而不能是任何类型的任意值

  • WeakSet弱引用,集合中对象引用为弱引用,如果没有其他对WeakSet对象的引用,则会被GC回收

最后,WeakRef实例有一个方法deref,返回引用的原始对象,如果原始对象被回收,则返回undefined

  1. const cache = new Map()

  2. const setValue = (key, obj) => {

  3. cache.set(key, new WeakRef(obj))

  4. }

  5. const getValue = (key) => {

  6. const ref = cache.get(key)

  7. if (ref) {

  8. return ref.deref()

  9. }

  10. }

  11. const fibonacciCached = (number) => {

  12. const cached = getValue(number)

  13. if (cached) return cached

  14. const sum = calculateFibonacci(number)

  15. setValue(number, sum)

  16. return sum

  17. }

对于缓存远程数据来说,这可能不是一个好主意,因为远程数据可能会不可预测地从内存中删除。在这种情况下,最好使用LRU之类的缓存。

逻辑运算符和赋值表达式

  1. a ||= b

  2. //等价于

  3. a = a || (a = b)


  4. a &&= b

  5. //等价于

  6. a = a && (a = b)


  7. a ??= b

  8. //等价于

  9. a = a ?? (a = b)

??= 可用来初始化缺失的属性

  1. const pages = [

  2. {

  3. title:'主要场景',

  4. path:'/'

  5. },

  6. {

  7. path:'/a'

  8. },

  9. {

  10. path:'/b'

  11. },

  12. ]


  13. for (const page of pages){

  14. page.title ??= '默认标题'

  15. }


  16. console.table(pages)

  17. //(index) title path

  18. //0 "主要场景" "/"

  19. //1 "默认标题" "/a"

  20. //2 "默认标题" "/b"

小结:

  • a ||= b:当a值不存在时,将b变量赋值给a

  • a &&= b:当a值存在时,将b变量赋值给a

  • a ??= b:当a值为null或者undefined时,将b变量赋值给a

参考文章

  • https://backbencher.dev/javascript/es2021-new-features

  • https://codeburst.io/exciting-features-of-javascript-es2021-es12-1de8adf6550b

关于本文 作者:@五米 原文:https://jelly.jd.com/article/5febdfbb846cc00148ae36d7

为你推荐


【第1462期】赶上 ECMAScript 潮流:用现代 JavaScript 编程


【第1877期】理解ECMAScript规范(一)


欢迎自荐投稿,前端早读课等你来

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存